﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using FarseerPhysics.SamplesFramework;
using Microsoft.Xna.Framework.Graphics;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using FarseerPhysics;
using FarseerPhysics.Dynamics.Contacts;
using Sample.data;

namespace FarseerPhysics.SamplesFramework
{
    public class Screen1 : PhysicsGameScreen
    {
        const float BirdSize = 30;
        const float PigSize = 30;
        const float Bricksize = 30;
        //public void Exit();
        static readonly Vector2 PivitPoint = new Vector2(70, 500);

        Texture2D brickPiece1;
        Texture2D pigTexture;
        Texture2D brickTexture;
        Texture2D birdTexture;
        Texture2D grass;

        LevelInfo level;
        Body pig;
        Body ground;

        Vector2 Offset;
        const int MAX_SIZE = 20;
        Body[] pieceArray = new Body[MAX_SIZE]; 

        List<Body> bricks = new List<Body>();
        List<Body> birds = new List<Body>();
        List<Body> brickPiece = new List<Body>();

        Vector2 changeXAML = new Vector2(0, 105);
        MouseState mouseStateLastFrame;
        private Texture2D background;
        private Rectangle _viewport;
        public override void LoadContent()
        {
            base.LoadContent();
            background = ScreenManager.Content.Load<Texture2D>(@"Man3/background1");
            grass = ScreenManager.Content.Load<Texture2D>(@"Man3/grass1");
            birdTexture = ScreenManager.Content.Load<Texture2D>(@"Man3/Element130");
            pigTexture = ScreenManager.Content.Load<Texture2D>(@"Man3/Element76");
            brickTexture = ScreenManager.Content.Load<Texture2D>(@"Man3/Element29");
            brickPiece1 = ScreenManager.Content.Load<Texture2D>(@"Man3/Element53");
            level = ScreenManager.Content.Load<LevelInfo>(@"Level/Level01");
            
            Settings.PositionIterations = 100;
            World = new World(Vector2.UnitY * 9.8f);
            World.ContactManager.PostSolve = PostSolveDelegate;
            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
            _viewport = new Rectangle(viewport.X-viewport.Bounds.Width/2, viewport.Y-viewport.Bounds.Height/2, viewport.Bounds.Width, viewport.Bounds.Height);
            Offset = new Vector2(viewport.Width/2, viewport.Height/2);
            for (int i = 0; i < MAX_SIZE; i++)
            {
                pieceArray[i] = BodyFactory.CreateRectangle(World,ConvertUnits.ToSimUnits(brickPiece1.Width / 2),ConvertUnits.ToSimUnits(brickPiece1.Height / 2) , 1);
            }
            for (int i = 0; i < 10; i++)
            {
                for (int j = i + 1; j < 10; j++)
                {
                    pieceArray[i].IgnoreCollisionWith(pieceArray[j]);
                }
            }

            foreach (var brick in level.Bricks)
            {
                //var body = BodyFactory.CreateCapsule(world, brick.Size.X * ViewToPhysics, brick.Size.Y * ViewToPhysics, 1);
                var body = BodyFactory.CreateRectangle(World, ConvertUnits.ToSimUnits(brick.Size.X), ConvertUnits.ToSimUnits(brick.Size.Y), 1);
                body.BodyType = BodyType.Dynamic;

                body.Position = ConvertUnits.ToSimUnits(new Vector2(brick.Position.X + brick.Size.X / 2, brick.Position.Y + brick.Size.Y / 2) - Offset + changeXAML);
                body.Restitution = 0.2f;
                body.Friction = 0.8f;
                body.UserData = brick;
                for (int i = 0; i < MAX_SIZE; i++)
                {
                    pieceArray[i].IgnoreCollisionWith(body);
                }
                bricks.Add(body);
            }
            foreach (var bird in level.Birds)
            {
                var body = BodyFactory.CreateCircle(World,ConvertUnits.ToSimUnits(BirdSize * 0.5f) , 1);
                body.BodyType = BodyType.Dynamic;
                body.Position = ConvertUnits.ToSimUnits(new Vector2(bird.X + BirdSize / 2, bird.Y + BirdSize / 2) - Offset + changeXAML) ;
                body.Restitution = 0.2f;
                body.Friction = 0.8f;
                for (int i = 0; i < MAX_SIZE; i++)
                {
                    pieceArray[i].IgnoreCollisionWith(body);
                }
                birds.Add(body);
            }
            pig = BodyFactory.CreateCircle(World, ConvertUnits.ToSimUnits(PigSize * 0.5f), 1);
            pig.BodyType = BodyType.Static;
            pig.Position = ConvertUnits.ToSimUnits(PivitPoint - Offset);
            pig.Restitution = 0.2f;
            pig.Friction = 0.8f;
            for (int i = 0; i < MAX_SIZE; i++)
            {
                pieceArray[i].IgnoreCollisionWith(pig);
            }

            ground = BodyFactory.CreateRectangle(World, ConvertUnits.ToSimUnits(1500), ConvertUnits.ToSimUnits(20), 1);
            ground.BodyType = BodyType.Kinematic;
            ground.Friction = 0.8f;
            ground.Position = ConvertUnits.ToSimUnits(new Vector2(100, 570) - Offset);

            //world has gravity
            World.Gravity = Vector2.UnitY * 9.8f;
        }


        public override void HandleInput(InputHelper input, GameTime gameTime)
        {

            var mouseState = input.MouseState;

            if (mouseState.LeftButton == ButtonState.Pressed && pig.BodyType == BodyType.Static)
            {
                pig.Position = ConvertUnits.ToSimUnits(ClampPosition(new Vector2(mouseState.X, mouseState.Y)-Offset));
            }

            if (mouseState.LeftButton == ButtonState.Released && mouseStateLastFrame.LeftButton == ButtonState.Pressed &&
                pig.BodyType == BodyType.Static)
            {
                pig.Position = ConvertUnits.ToSimUnits(ClampPosition(new Vector2(mouseState.X, mouseState.Y))) ;
                pig.BodyType = BodyType.Dynamic;

                Vector2 force = (ConvertUnits.ToSimUnits(PivitPoint) - pig.Position)*100;
                pig.ApplyLinearImpulse(force*0.1f);
            }

            if (mouseState.LeftButton == ButtonState.Released && pig.BodyType == BodyType.Dynamic &&
               (!pig.Awake || IsOutsideBounds(pig.Position )) || Keyboard.GetState().IsKeyDown(Keys.Space))
            {
                pig.Position =ConvertUnits.ToSimUnits(PivitPoint) ;
                pig.BodyType = BodyType.Static;
            }
            mouseStateLastFrame = mouseState;

            World.Step(Math.Min((float)gameTime.ElapsedGameTime.TotalSeconds, 1.0f / 30));

            base.HandleInput(input, gameTime);
        }
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                   bool coveredByOtherScreen)
        {
           
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
        }
        private void PostSolveDelegate(Contact contact, ContactConstraint impulse)
        {
            float maxImpulse = 0;
            for (int i = 0; i < impulse.Manifold.PointCount; i++)
            {
                maxImpulse = Math.Max(maxImpulse, impulse.Manifold.Points[i].NormalImpulse);
            }

            if (maxImpulse > 2)
            {
                if (birds.Contains(impulse.BodyA))
                {
                    birds.Remove(impulse.BodyA);
                    World.RemoveBody(impulse.BodyA);
                }
                if (birds.Contains(impulse.BodyB))
                {
                    birds.Remove(impulse.BodyB);
                    World.RemoveBody(impulse.BodyB);
                }
                if ((pig == impulse.BodyA) && (bricks.Contains(impulse.BodyB)))
                {
                    Random r = new Random();
                    Random ar = new Random();
                    for (int i = 0; i < MAX_SIZE; i++)
                    {
                        float anguleRotation = ConvertUnits.ToSimUnits(ar.Next(-10, 10));
                        Vector2 randomPosition = ConvertUnits.ToSimUnits(new Vector2(r.Next(-60, 60), r.Next(-60, 60)));
                        bricks.Remove(impulse.BodyB);
                        World.RemoveBody(impulse.BodyB);
                        pieceArray[i].Position = impulse.BodyB.Position + randomPosition;
                        pieceArray[i].Restitution = 0.2f;
                        pieceArray[i].Friction = 0.8f;
                        pieceArray[i].Rotation = anguleRotation;
                        pieceArray[i].AngularVelocity = 100f;
                        pieceArray[i].BodyType = BodyType.Dynamic;
                        OrientedBox ord1 = new OrientedBox();
                        ord1.Position = impulse.BodyB.Position + randomPosition;
                        ord1.Size = new Vector2(brickPiece1.Width / 2, brickPiece1.Height / 2);

                        pieceArray[i].UserData = ord1;
                        brickPiece.Add(pieceArray[i]);
                    }
                }
                if ((pig == impulse.BodyB) && (bricks.Contains(impulse.BodyA)))
                {
                    Random r = new Random();
                    Random ar = new Random();
                    for (int i = 0; i < MAX_SIZE; i++)
                    {
                        float anguleRotation = ConvertUnits.ToSimUnits(ar.Next(-10, 10));
                        Vector2 randomPosition = ConvertUnits.ToSimUnits(new Vector2(r.Next(-60, 60), r.Next(-60, 60)));
                        bricks.Remove(impulse.BodyA);
                        World.RemoveBody(impulse.BodyA);
                        pieceArray[i].Position = impulse.BodyA.Position + randomPosition;
                        pieceArray[i].Restitution = 0.2f;
                        pieceArray[i].Friction = 0.8f;
                        pieceArray[i].Rotation = anguleRotation;
                        pieceArray[i].AngularVelocity = 100f;
                        pieceArray[i].BodyType = BodyType.Dynamic;
                        OrientedBox ord1 = new OrientedBox();
                        ord1.Position = impulse.BodyA.Position + randomPosition;
                        ord1.Size = new Vector2(brickPiece1.Width / 2, brickPiece1.Height / 2);
                        pieceArray[i].UserData = ord1;
                        brickPiece.Add(pieceArray[i]);
                    }
                }
            }
        }
        private Vector2 ClampPosition(Vector2 position)
        {
            Vector2 direction = PivitPoint - position;
            float inv = MathHelper.Clamp(direction.Length(), 10, 60) / direction.Length();
            direction.X *= inv;
            direction.Y *= inv;
            return PivitPoint - direction;
        }
        private bool IsOutsideBounds(Vector2 position)
        {
            return !new Rectangle(-100, -100, 1000, 600).Contains(new Point((int)position.X, (int)position.Y));
        }

        public override void Draw(GameTime gameTime)
        {
            ScreenManager.SpriteBatch.Begin(0, null, null, null, null, null, Camera.View);
            ScreenManager.SpriteBatch.Draw(background, _viewport, Color.White);
            ScreenManager.SpriteBatch.Draw(grass, ConvertUnits.ToDisplayUnits(ground.Position), Color.White);
            foreach (var body in brickPiece)
            {
                ScreenManager.SpriteBatch.Draw(brickPiece1, ConvertUnits.ToDisplayUnits(body.Position), null, Color.White, body.Rotation,
                    new Vector2(brickPiece1.Width * 0.5f, brickPiece1.Height * 0.5f),
                    new Vector2(((OrientedBox)body.UserData).Size.X / brickPiece1.Width,
                                ((OrientedBox)body.UserData).Size.Y / brickPiece1.Height), SpriteEffects.None, 0);
            }

            foreach (var body in bricks)
            {
                ScreenManager.SpriteBatch.Draw(brickTexture, ConvertUnits.ToDisplayUnits(body.Position), null, Color.White, body.Rotation,
                    new Vector2(brickTexture.Width * 0.5f, brickTexture.Height * 0.5f),
                    new Vector2(((OrientedBox)body.UserData).Size.X / brickTexture.Width,
                                ((OrientedBox)body.UserData).Size.Y / brickTexture.Height), SpriteEffects.None, 0);
            }

            foreach (var body in birds)
            {
                ScreenManager.SpriteBatch.Draw(birdTexture, ConvertUnits.ToDisplayUnits(body.Position), null, Color.White, body.Rotation,
                    new Vector2(birdTexture.Width * 0.5f, birdTexture.Height * 0.5f),
                    new Vector2((BirdSize / birdTexture.Width),
                                (BirdSize / birdTexture.Height)), SpriteEffects.None, 0);
            }

            ScreenManager.SpriteBatch.Draw(pigTexture, ConvertUnits.ToDisplayUnits(pig.Position), null, Color.White, pig.Rotation,
                    new Vector2(pigTexture.Width * 0.5f, pigTexture.Height * 0.5f),
                    new Vector2((PigSize / pigTexture.Width),
                                (PigSize / pigTexture.Height)), SpriteEffects.None, 0);

            ScreenManager.SpriteBatch.End();
            base.Draw(gameTime);

        }
    }
}
